#pragma once

#include <vector>
#include <functional>
#include <pthread.h>
#include "Socket.hpp"

namespace Tcpserver
{
    using func_t = std::function<void(int)>;

    class TcpServer;
    class ThreadInfo
    {
    public:
        ThreadInfo(int socket, TcpServer *server)
            : _socket(socket),
              _ptrServer(server)
        {
        }

        ~ThreadInfo() {}

    public:
        int _socket;
        TcpServer *_ptrServer;
    };

    class TcpServer
    {
    private:
        static void *ThreadRoutine(void *args)
        {
            pthread_detach(pthread_self());

            ThreadInfo *threadinfo = static_cast<ThreadInfo *>(args);
            threadinfo->_ptrServer->Excute(threadinfo->_socket);
            
            close(threadinfo->_socket);
            delete threadinfo;
            
            return nullptr;
        }
    public:
        TcpServer(const uint16_t &port, const std::string &ip = "0.0.0.0")
        {
            _listenSocket = _socket.Socket();
            _socket.Bind(_listenSocket, port, ip);
            _socket.Listen(_listenSocket);
        }

        void Start()
        {
            while (true)
            {
                std::string clientIp;
                uint16_t clientPort;

                int serviceSocket = _socket.Accept(_listenSocket, &clientIp, &clientPort);
                if (serviceSocket == -1)
                    continue;

                logMsg(NORMAL, "create new link success, sock: %d", serviceSocket);
                pthread_t tid;
                ThreadInfo *threadinfo = new ThreadInfo(serviceSocket, this);
                pthread_create(&tid, nullptr, ThreadRoutine, threadinfo);
            }
        }

        void AddService(func_t func)
        {
            _func.push_back(func);
        }

        void Excute(int socket)
        {
            for (auto &fun : _func)
            {
                fun(socket);
            }
        }

        ~TcpServer()
        {
            if (_listenSocket >= 0)
                close(_listenSocket);
        }

    private:
        int _listenSocket;
        Sock _socket;
        std::vector<func_t> _func;
    };
}